昨天延伸了類別講到了物件與單例,熟悉 Java 的讀者這時候可能會想到,在 Java 裡面還有一個靜態變數呼現在都還有提到。沒錯,在 Java 內我們常會用 static
字樣在同一種類別之間做出一個具有單例特性的變數,但確實在 Kotlin 這項設計並沒有直接被 Kotlin 採用。
那麼問題來了,要怎麼去滿足只共享於相同類別的單例的需求呢?Kotlin 提供了 companion object
(伴生物件) 這樣的方法。
在 Kotlin 裡,伴生物件宣告在類別內部,用於定義與類別本身相關而不是類別實例相關的靜態變數或函式。
class Person(val name: String, val age: Int) {
companion object {
const val species = "Homo sapiens"
fun createDefaultPerson(): Person {
return Person("Unknown", 0)
}
}
fun greet() {
println("你好,我叫 $name,我 $age 歲。")
}
}
在上述範例中,我們在 Person
類別裡加入了一個伴生物件。這個伴生物件有一個常數變數 species
和一個函式 createDefaultPerson()
,該函式會返回有預設傳入參數的 Person
物件。如果我們想要一個類別裡的存取伴生物件,可以使用類別名稱後跟 companion object
內容的變數或函示名稱:
val defaultPerson = Person.createDefaultPerson()
println("預設人物:${defaultPerson.name},${defaultPerson.age}") // 預設人物:Unknown,0
println("物種:${Person.species}") // 物種:Homo sapiens
這裡我們可以發現,跟在 Java 使用靜態變數相似,我們可以不用真的從 Person
這個類別去建立一個新物件才可以使用伴生物件的內容;反之,我們可以直接使用 Person
類別內的伴生物件,而上述案例則會在伴生物件內直接生成一個 Person
物件。
讓我們再用一個範例看另一個伴生物件的功用:
class Person{
private val heightCm = 170
companion object {
fun getHeightCm(instance: Person): Int {
return instance.heightCm
}
}
}
val john = Person()
val johnHeight = Person.getHeightCm(john) // 成功獲得 170
println(johnHeight) // 170
從上面的範例中,若我們將伴生物件換成單例,我們將無法存取 Person
這個伴生物件的類別中的私有變數,這也是會需要使用到伴生物件的場景之一。